package main

import "fmt"

func calc(taskChan chan int, resChan chan int, exitChan chan bool) {

	for v := range taskChan {
		flag := true
		for i := 2; i < v; i++ {
			if v%i == 0 { // 判断不是素数的内容
				flag = false
				break
			}
		}
		if flag {
			resChan <- v // 将素数写入管道
		}
	}
	fmt.Println("exit")
	exitChan <- true // 结束时将结束标记写入结束的管道
}

func main() {
	// 定义三个管道，intChan里存1000个数字，在这些数字里判断素数
	intChan := make(chan int, 1000)
	// resultChan里存判断出来的素数
	resultChan := make(chan int, 1000)
	// exitChan里存储进程结束的信号，用来判断子进程是否都结束了
	exitChan := make(chan bool, 8)

	go func() { // 启动一个线程往intChan管道里写入1000个数
		for i := 0; i < 1000; i++ {
			intChan <- i
		}
		// 1000个数写完后关闭管道（不能往管道里写数据了、用for range循环完intChan管道后会自动退出循环）
		close(intChan)
	}()

	// 启动8个携程执行计算素数的函数
	for i := 0; i < 8; i++ {
		go calc(intChan, resultChan, exitChan) // calc(数据管道, 结果管道, 退出信号管道)
	}

	// 启动一个线程，获取所有计算素数子进程的退出新号（从退出信号管道里获取八个退出信息号，证明八个goroutine全部退出了）
	go func() {
		for i := 0; i < 8; i++ {
			<-exitChan // 只从管道里把内容取出来（不需要获取）可以这么写（ <- exitChan），不用使用变量接，就是从管道里取出内容丢掉
			fmt.Println("wait goroutine", i, "exited")
		}
		close(resultChan) // 所有计算素数的goroutine退出后关闭结果管道
	}()

	// 循环读取计算后得到的素数（管道关掉之后for range循环完毕之后就会自动退出循环）
	for v := range resultChan {
		fmt.Println(v)
	}
}
